home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
fish
/
676-700
/
681
/
term
/
source.lha
/
termAux.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-05-09
|
65KB
|
3,343 lines
/*
** $Id: termAux.c,v 1.12 92/05/08 20:50:59 olsen Sta Locker: olsen $
** $Revision: 1.12 $
** $Date: 92/05/08 20:50:59 $
**
** Miscellaneous support routines
**
** Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
** All Rights Reserved
*/
#include "termGlobal.h"
/* Some handy positioning macros for StatusServer(). */
#define MoveItem(X,Y) Move(RPort,StatusOffset + X * 8,10 + Y * 13)
#define MoveSingle(X) Move(RPort,StatusOffset + X * 8,7)
/* The following static strings are displayed in the status
* window.
*/
STATIC UBYTE *ConfigFont[2] =
{
"Topaz",
"IBM® "
};
STATIC UBYTE *ConfigEmulation[4] =
{
NULL,
NULL,
NULL,
NULL
};
STATIC UBYTE *ConfigParity[5] =
{
NULL,
NULL,
NULL,
NULL,
NULL
};
STATIC UBYTE *ConfigStatus[7] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
/* Block window nest count. */
STATIC WORD BlockNestCount;
/* ExtractString():
*
* Extracts a string from a list separated by `|' characters.
*/
UBYTE * __regargs
ExtractString(UBYTE *String,UBYTE *Destination,BYTE ReturnEnd)
{
UBYTE *OldString;
if(ReturnEnd)
OldString = NULL;
else
OldString = String;
while(*String)
{
if(*String == '|')
{
*Destination = 0;
String++;
if(*String)
return(String);
else
return(OldString);
}
else
*Destination++ = *String++;
}
*Destination = 0;
return(OldString);
}
/* DeleteInterleavedBitMap():
*
* Delete an interleaved bitmap as allocated by
* CreateInterleavedBitMap().
*/
VOID __regargs
DeleteInterleavedBitMap(struct BitMap *SomeBitMap)
{
FreeVec(SomeBitMap -> Planes[0]);
FreeVec(SomeBitMap);
}
/* CreateInterleavedBitMap():
*
* With special thanks to Leo Schwab, this routine will create an
* interleaved BitMap structure suitable for optimized blitter
* access.
*/
struct BitMap * __regargs
CreateInterleavedBitMap(LONG Width,LONG Height,WORD Depth)
{
/* A single plane BitMap cannot be interleaved. */
if(Depth > 1)
{
struct BitMap *SomeBitMap;
/* Allocate space for the bitmap structure. */
if(SomeBitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
{
/* Initialize with standard values, so we can check
* whether the current system will be able to handle
* an interleaved bitmap of the expected size.
*/
InitBitMap(SomeBitMap,Depth,Width,Height);
/* Check for old standard blitter limits. */
if(Height * Depth > 1024 || SomeBitMap -> BytesPerRow * Depth > 126)
{
/* The current space requirements will operate
* correctly only on a system equipped with a
* Fat Agnus (or successor) chip, let's see
* if we can find one.
*/
if(!(GfxBase -> ChipRevBits0 & GFXF_BIG_BLITS))
{
/* Looks like a Big or old (A1000)
* Agnus chip.
*/
FreeVec(SomeBitMap);
return(NULL);
}
else
{
/* Unlikely, put still not impossible: check for
* Fat Agnus size limits...
*/
if(Height * Depth > 32768 || SomeBitMap -> BytesPerRow * Depth > 4096)
{
FreeVec(SomeBitMap);
return(NULL);
}
}
}
/* Initialize to interleaved BitMap values. */
InitBitMap(SomeBitMap,1,Width,Height * Depth);
/* Allocate plane data. */
if(SomeBitMap -> Planes[0] = (PLANEPTR)AllocVec(SomeBitMap -> BytesPerRow * SomeBitMap -> Rows,MEMF_CHIP))
{
PLANEPTR Base;
WORD i,
Size;
/* Remember previous data. */
Base = SomeBitMap -> Planes[0];
Size = SomeBitMap -> BytesPerRow;
/* Clear the bitmap. */
BltBitMap(SomeBitMap,0,0,SomeBitMap,0,0,Width,Height,0,~0,NULL);
/* Reinitialize. */
InitBitMap(SomeBitMap,Depth,Width,Height);
/* Modify for interleaved look. */
SomeBitMap -> BytesPerRow *= Depth;
/* Initialize the single planes. */
for(i = 0 ; i < Depth ; i++)
{
SomeBitMap -> Planes[i] = Base;
Base += Size;
}
/* Return the ready bitmap. */
return(SomeBitMap);
}
/* Deallocate memory. */
FreeVec(SomeBitMap);
}
}
/* Return failure. */
return(NULL);
}
/* GetListNode(LONG Offset,struct List *List):
*
* Return the n-th Node entry in a standard exec list.
*/
struct Node *
GetListNode(LONG Offset,struct List *List)
{
struct Node *Node;
LONG i;
Node = List -> lh_Head;
for(i = 0 ; i < Offset ; i++)
{
if(!Node -> ln_Succ -> ln_Succ)
return(NULL);
Node = Node -> ln_Succ;
}
return(Node);
}
/* GetConUnit():
*
* Extract the ConUnit pointer from the current output stream
* console.
*/
struct ConUnit *
GetConUnit(struct MsgPort *ConsoleTask)
{
struct InfoData *InfoData;
struct ConUnit *ConUnit = NULL;
if(!ConsoleTask)
{
ConsoleTask = (struct MsgPort *)((struct Process *)SysBase -> ThisTask) -> pr_ConsoleTask;
if(!TypeOfMem(ConsoleTask))
return(NULL);
}
if(InfoData = (struct InfoData *)AllocVec(sizeof(struct InfoData),MEMF_ANY|MEMF_CLEAR))
{
/* Send the inquiry packet to the console task. */
if(DoPkt1(ConsoleTask,ACTION_DISK_INFO,MKBADDR(InfoData)))
ConUnit = (struct ConUnit *)((struct IOStdReq *)InfoData -> id_InUse) -> io_Unit;
FreeVec(InfoData);
}
return(ConUnit);
}
/* AddDownloadObject(UBYTE *Line):
*
* Add another downloaded object to the list.
*/
VOID
AddDownloadObject(UBYTE *Line)
{
struct Node *SomeNode;
/* Allocate space for the node itself and the
* string to be put into the node name.
*/
if(SomeNode = (struct Node *)AllocVec(sizeof(struct Node) + strlen(Line) + 1,MEMF_ANY|MEMF_CLEAR))
{
/* Block list modification. */
ObtainSemaphore(DownloadSemaphore);
/* Enter the name. */
SomeNode -> ln_Name = (UBYTE *)(SomeNode + 1);
/* Copy the line over. */
strcpy(SomeNode -> ln_Name,Line);
/* Add it to the list. */
AddTail(&DownloadList,SomeNode);
/* Increment number of downloads. */
DownloadLineCount++;
ReleaseSemaphore(DownloadSemaphore);
}
}
/* ClearDownloadObjects():
*
* Clear the list of downloaded objects.
*/
VOID
ClearDownloadObjects()
{
struct Node *SomeNode,*NextNode;
ObtainSemaphore(DownloadSemaphore);
SomeNode = DownloadList . lh_Head;
while(SomeNode -> ln_Succ)
{
NextNode = SomeNode -> ln_Succ;
Remove(SomeNode);
FreeVec(SomeNode);
SomeNode = NextNode;
}
DownloadNode = NULL;
DownloadLineCount = 0;
ReleaseSemaphore(DownloadSemaphore);
}
/* SequenceFilter(UBYTE Char):
*
* Yet another byte sequence filter, this time it's the
* ARexx interface to make the call.
*/
struct ScanNode *
SequenceFilter(UBYTE Char)
{
struct ScanNode *SomeNode,*Matching = NULL;
BYTE Matches = 0;
/* Convert input character to upper case. */
Char = ToUpper(Char);
/* Get the first node in the list. */
SomeNode = (struct ScanNode *)SequenceList . lh_Head;
/* Scan until the last node is found. */
while(SomeNode -> Node . mln_Succ)
{
/* This sequence had a couple of matches. */
if(SomeNode -> Count == SequenceCount)
{
/* The next character in the sequence
* still matches.
*/
if(Char == SomeNode -> Sequence[SequenceCount])
{
/* Increase number of matching
* characters.
*/
SomeNode -> Count++;
/* If there's another character
* in the sequence, increase
* the match counter.
*/
if(SomeNode -> Sequence[SequenceCount + 1])
Matches++;
else
{
/* We were able to make
* a perfect match.
*/
Matches = 0;
Matching = SomeNode;
}
}
}
/* Skip to the next node. */
SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
}
if(!Matches)
{
/* Clear the list entry counters. */
if(SequenceCount)
{
SomeNode = (struct ScanNode *)SequenceList . lh_Head;
while(SomeNode -> Node . mln_Succ)
{
SomeNode -> Count = 0;
SomeNode = (struct ScanNode *)SomeNode -> Node . mln_Succ;
}
SequenceCount = 0;
}
}
else
SequenceCount++;
return(Matching);
}
/* AddSequenceObject(UBYTE *Sequence):
*
* Add another sequence to the list of byte sequences
* the routine above will look at whilst parsing.
*/
VOID
AddSequenceObject(UBYTE *Sequence)
{
struct ScanNode *SomeNode;
if(SomeNode = AllocVec(sizeof(struct ScanNode) + strlen(Sequence) + 1,MEMF_ANY|MEMF_CLEAR))
{
WORD i;
SomeNode -> Sequence = (UBYTE *)(SomeNode + 1);
for(i = 0 ; i <= strlen(Sequence) ; i++)
SomeNode -> Sequence[i] = ToUpper(Sequence[i]);
AddTail(&SequenceList,(struct Node *)SomeNode);
}
}
/* ClearSequenceObjects():
*
* Clear the list of scan sequences.
*/
VOID
ClearSequenceObjects()
{
struct Node *SomeNode,*NextNode;
SomeNode = SequenceList . lh_Head;
while(SomeNode -> ln_Succ)
{
NextNode = SomeNode -> ln_Succ;
Remove(SomeNode);
FreeVec(SomeNode);
SomeNode = NextNode;
}
}
/* LogAction(UBYTE *String,...):
*
* Write an action to the default log file.
*/
VOID __stdargs
LogAction(UBYTE *String,...)
{
if(Config . LogActions && Config . LogFile[0])
{
UBYTE DummyBuffer[512];
BPTR File;
va_list VarArgs;
/* Build a valid string. */
va_start(VarArgs,String);
VSPrintf(DummyBuffer,String,VarArgs);
va_end(VarArgs);
/* Does the log file already exist? */
if(GetFileSize(Config . LogFile))
{
/* It does, let's append the data. */
if(File = Open(Config . LogFile,MODE_READWRITE))
{
if(Seek(File,0,OFFSET_END) == -1)
{
Close(File);
File = NULL;
}
}
}
else
{
/* Create a new file. */
if(File = Open(Config . LogFile,MODE_NEWFILE))
FPrintf(File,LocaleString(MSG_TERMAUX_DATE_TIME_ACTION_TXT));
}
/* The file is open, build the date/time string and
* write the log action.
*/
if(File)
{
UBYTE TimeBuffer[20],DateBuffer[20];
struct DateTime DateTime;
/* Obtain current time. */
DateStamp(&DateTime . dat_Stamp);
/* Convert it to human readable form. */
DateTime . dat_Format = FORMAT_DOS;
DateTime . dat_Flags = 0;
DateTime . dat_StrDay = NULL;
DateTime . dat_StrDate = DateBuffer;
DateTime . dat_StrTime = TimeBuffer;
/* Conversion succeeded? */
if(DateToStr(&DateTime))
FPrintf(File,"%s %s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
/* Done! */
Close(File);
}
}
}
/* FlushMsg(struct Window *Window):
*
* Cancel all pending messages of a window.
*/
VOID
FlushMsg(struct Window *Window)
{
struct IntuiMessage *Massage;
while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
ReplyMsg(&Massage -> ExecMessage);
}
/* GetString(UBYTE *Prompt,UBYTE *Buffer):
*
* Get a string from the user, very much the same as xpr_gets,
* but also including the `Load File' gadget.
*/
BYTE
GetString(UBYTE *Prompt,UBYTE *Buffer)
{
struct Gadget *GadgetList = NULL;
struct Gadget *GadgetArray[4];
struct Window *PanelWindow;
UBYTE DummyBuffer[256];
struct FileRequester *FileRequest;
LONG Width;
BYTE Success = FALSE;
if(CreateAllGetsGadgets(TRUE,Buffer,Prompt,&Width,&GadgetArray[0],&GadgetList,VisualInfo,Screen -> WBorTop + Screen -> Font -> ta_YSize + 1,Screen))
{
if(PanelWindow = OpenWindowTags(NULL,
WA_Width, Width,
WA_Height, 58,
WA_Left, (Screen -> Width - Width) >> 1,
WA_Top, (Screen -> Height - 56) >> 1,
WA_Activate, TRUE,
WA_DragBar, TRUE,
WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE,
WA_RMBTrap, TRUE,
WA_CustomScreen,Screen,
WA_IDCMP, IDCMP_GADGETDOWN | IDCMP_ACTIVEWINDOW | IDCMP_CLOSEWINDOW | IDCMP_GADGETUP | IDCMP_VANILLAKEY | BUTTONIDCMP | STRINGIDCMP,
WA_Title, LocaleString(MSG_GLOBAL_ENTER_TEXT_TXT),
TAG_DONE))
{
struct IntuiMessage *Massage;
ULONG Class,Code;
struct Gadget *Gadget;
BYTE Terminated = FALSE;
PushWindow(PanelWindow);
AddGList(PanelWindow,GadgetList,(UWORD)-1,(UWORD)-1,NULL);
RefreshGList(GadgetList,PanelWindow,NULL,(UWORD)-1);
GT_RefreshWindow(PanelWindow,NULL);
ActiveGadget = NULL;
while(!Terminated)
{
WaitPort(PanelWindow -> UserPort);
while(!Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(PanelWindow -> UserPort)))
{
Class = Massage -> Class;
Code = Massage -> Code;
Gadget = (struct Gadget *)Massage -> IAddress;
GT_ReplyIMsg(Massage);
if(Class == IDCMP_VANILLAKEY)
KeySelect(GadgetArray,3,Code,PanelWindow,&Gadget,&Class,&Code);
if(Class == IDCMP_GADGETDOWN)
{
if((Gadget -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET)
ActiveGadget = Gadget;
}
if(Class == IDCMP_ACTIVEWINDOW && ActiveGadget)
ActivateGadget(ActiveGadget,PanelWindow,NULL);
if(Class == IDCMP_CLOSEWINDOW)
Terminated = TRUE;
if(Class == IDCMP_GADGETUP)
{
switch(Gadget -> GadgetID)
{
case 0: if(Code != '\t')
{
strcpy(Buffer,GT_STRING(GadgetArray[0]));
Success = TRUE;
Terminated = TRUE;
}
break;
case 1: strcpy(Buffer,GT_STRING(GadgetArray[0]));
Success = TRUE;
Terminated = TRUE;
break;
case 2: BlockWindow(PanelWindow);
if(FileRequest = GetFile(LocaleString(MSG_TERMAUX_LOAD_FILE_TXT),"","",DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_LOAD_TXT)))
{
GT_SetGadgetAttrs(GadgetArray[0],PanelWindow,NULL,
GTST_String,DummyBuffer,
TAG_DONE);
FreeAslRequest(FileRequest);
}
ReleaseWindow(PanelWindow);
break;
case 3: Terminated = TRUE;
break;
}
}
}
}
ActiveGadget = NULL;
RemoveGList(PanelWindow,GadgetList,(UWORD)-1);
PopWindow();
CloseWindow(PanelWindow);
}
}
FreeGadgets(GadgetList);
return(Success);
}
/* WakeUp(struct Window *Window):
*
* Pop a window to the front and alert the user.
*/
VOID __regargs
WakeUp(struct Window *Window,BYTE Activate)
{
if(Window)
{
if(Window -> WScreen -> LeftEdge > 0)
{
if(Window -> WScreen -> TopEdge > 0)
MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,-Window -> WScreen -> TopEdge);
else
MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,0);
}
else
{
if(Window -> WScreen -> TopEdge > 0)
MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge);
}
ScreenToFront(Window -> WScreen);
if(Activate)
ActivateWindow(Window);
}
Beep();
if(Activate)
WaitTime(2,0);
}
/* SendAmigaDOSCommand(UBYTE *Name):
*
* Let the current default Shell execute an AmigaDOS
* command. Block until the command has returned.
*/
VOID
SendAmigaDOSCommand(UBYTE *Name)
{
BYTE DummyBuffer[2];
BPTR File;
/* Let the asynchronous Rexx server pick up and process
* all incoming messages rather than sending them to the
* main process (hopefully avoids deadlock situations).
*/
BatchMode = TRUE;
/* Open the console window or whatever the user
* wants us to open here.
*/
if(File = Open(WindowName,MODE_NEWFILE))
{
struct ConUnit *ConUnit = GetConUnit(((struct FileHandle *)BADDR(File)) -> fh_Type);
STRPTR WindowSpec;
if(ConUnit)
{
if(ConUnit -> cu_Window)
BumpWindow(ConUnit -> cu_Window);
}
/* Make the Shell execute the command. */
SystemTags(Name,SYS_Output,File,TAG_DONE);
/* Wait for some impressive user action. */
if(IsInteractive(File) && (WindowSpec = FilePart(WindowName)))
{
BYTE IsAuto = FALSE;
WORD i;
for(i = 0 ; i < strlen(WindowSpec) - 3 ; i++)
{
if(!Strnicmp(&WindowSpec[i],"WAIT",4))
{
IsAuto = TRUE;
break;
}
}
if(!IsAuto)
{
Write(File,LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT),strlen(LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT)));
Read(File,DummyBuffer,1);
}
}
Close(File);
}
/* Bring the `term' main screen to the front and
* fall back into asynchronous Rexx message processing.
*/
BumpWindow(Window);
BatchMode = FALSE;
}
/* RexxBackgroundServer():
*
* The background process to handle the rexx
* massaging.
*/
VOID __saveds
RexxBackgroundServer()
{
BPTR OldCOS,OldCIS,NewCOS,NewCIS;
struct MsgPort *OldConsoleTask,*ReplyPort;
BYTE DummyBuffer[2];
struct RexxMsg *RexxMsg;
struct Process *BackgroundProcess;
struct Message *SetupMsg;
/* Look who we are. */
BackgroundProcess = (struct Process *)SysBase -> ThisTask;
/* Wait for startup message. */
WaitPort(&BackgroundProcess -> pr_MsgPort);
/* Pick the message up. */
SetupMsg = GetMsg(&BackgroundProcess -> pr_MsgPort);
/* Create a reply port the Rexx message is to
* return to after processing.
*/
if(ReplyPort = (struct MsgPort *)CreateMsgPort())
{
/* Remember previous I/O streams and
* console handler.
*/
OldCOS = BackgroundProcess -> pr_COS;
OldCIS = BackgroundProcess -> pr_CIS;
OldConsoleTask = BackgroundProcess -> pr_ConsoleTask;
/* The following lines perform an `almost illegal'
* action: new console I/O streams are opened for
* the `term' main process. This is due to a rather
* helpful Rexx server feature. Errors, messages
* and other data are sent to the current output
* stream.
*/
if(NewCIS = Open(WindowName,MODE_NEWFILE))
{
struct FileHandle *FileHandle = (struct FileHandle *)BADDR(NewCIS);
struct ConUnit *ConUnit = GetConUnit(((struct FileHandle *)BADDR(NewCIS)) -> fh_Type);
/* Lock until we're done with the forgery. */
Forbid();
BackgroundProcess -> pr_ConsoleTask = (APTR)FileHandle -> fh_Type;
BackgroundProcess -> pr_CIS = NewCIS;
BackgroundProcess -> pr_COS = NewCOS = Open("*",MODE_NEWFILE);
Permit();
RexxWindow = NULL;
if(ConUnit)
{
if(RexxWindow = ConUnit -> cu_Window)
BumpWindow(RexxWindow);
}
/* Send the command and wait for a reply. */
if(SendRexxCommand(ReplyPort,SetupMsg -> mn_Node . ln_Name,".term",TermIDString))
{
ULONG SignalSet;
do
{
SignalSet = Wait((1 << ReplyPort -> mp_SigBit) | SIGBREAKF_CTRL_C);
if(SignalSet & SIGBREAKF_CTRL_C)
Signal(ThisProcess,SIGBREAKF_CTRL_D);
}
while(!(SignalSet & (1 << ReplyPort -> mp_SigBit)));
/* Pick up the RexxMsg (SendRexxCommand
* had allocated it for us) and
* examine the return codes.
*/
if(RexxMsg = (struct RexxMsg *)GetMsg(ReplyPort))
{
if(!ExitQuietly)
{
STRPTR WindowSpec;
/* This doesn't look too
* good, does it?
*/
if(RexxMsg -> rm_Result1)
FPrintf(NewCIS,LocaleString(MSG_TERMAUX_COMMAND_HAS_TERMINATED_TXT),SetupMsg -> mn_Node . ln_Name,RexxMsg -> rm_Result1,RexxMsg -> rm_Result2);
/* Show our hand and return
* to the usual business.
*/
if(IsInteractive(NewCIS) && (WindowSpec = FilePart(WindowName)))
{
BYTE IsAuto = FALSE;
WORD i;
for(i = 0 ; i < strlen(WindowSpec) - 3 ; i++)
{
if(!Strnicmp(&WindowSpec[i],"WAIT",4))
{
IsAuto = TRUE;
break;
}
}
if(!IsAuto)
{
Write(NewCIS,LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT),strlen(LocaleString(MSG_TERMAUX_PRESS_RETURN_TO_CONTINUE_TXT)));
Read(NewCIS,DummyBuffer,1);
}
}
Term2Front();
}
else
ExitQuietly = FALSE;
/* Release the message. */
FreeRexxCommand(RexxMsg);
}
}
Forbid();
RexxWindow = NULL;
Permit();
BumpWindow(Window);
/* Close our fake I/O streams. */
Forbid();
Close(NewCIS);
Close(NewCOS);
/* And install the previous pointers. */
BackgroundProcess -> pr_ConsoleTask = (APTR)OldConsoleTask;
BackgroundProcess -> pr_CIS = OldCIS;
BackgroundProcess -> pr_COS = OldCOS;
Permit();
}
/* Remove the reply port. */
DeleteMsgPort(ReplyPort);
}
/* We are done, lock and reply the message causing the
* main process to return to the input loop.
*/
Forbid();
ReplyMsg(SetupMsg);
}
/* SendARexxCommand(UBYTE *Name):
*
* Let the ARexx server execute a command (or a script
* file if necessary) and block until the command
* has returned.
*/
VOID
SendARexxCommand(UBYTE *Name)
{
struct Process *BackgroundProcess;
struct Message *SetupMsg;
struct MsgPort *ReplyPort;
ULONG SignalSet;
/* Create a reply port for the info message. */
if(ReplyPort = CreateMsgPort())
{
/* Allocate the message body. */
if(SetupMsg = (struct Message *)AllocVec(sizeof(struct Message),MEMF_ANY|MEMF_CLEAR))
{
/* Set up the message itself. */
SetupMsg -> mn_Node . ln_Name = Name;
SetupMsg -> mn_ReplyPort = ReplyPort;
SetupMsg -> mn_Length = sizeof(struct Message);
/* Create the background process which will
* handle all the messy rexx message sending
* for us.
*/
if(BackgroundProcess = (struct Process *)CreateNewProcTags(
NP_Entry, RexxBackgroundServer,
NP_Name, "term ARexx background process",
NP_StackSize, 16384,
TAG_END))
{
SetSignal(0,SIGBREAKF_CTRL_D);
/* Send the startup message. */
PutMsg(&BackgroundProcess -> pr_MsgPort,SetupMsg);
/* Go into loop and wait for the
* background process to return.
*/
FOREVER
{
SignalSet = Wait(SIG_REXX | (1 << ReplyPort -> mp_SigBit));
/* Yet another rexx message. */
if(SignalSet & SIG_REXX)
HandleRexx();
/* The background server has
* finished.
*/
if(SignalSet & (1 << ReplyPort -> mp_SigBit))
break;
}
SetSignal(0,SIGBREAKF_CTRL_D);
}
/* Free the message. */
FreeVec(SetupMsg);
}
/* Delete the reply port. */
DeleteMsgPort(ReplyPort);
}
}
/* ahtoi(UBYTE *String):
*
* Turn a hexadecimal string into an integer (borrowed from
* Matt Dillon's dmouse.c).
*/
LONG
ahtoi(UBYTE *String)
{
LONG Value = 0;
UBYTE c;
while(c = *String)
{
Value <<= 4;
if(c >= '0' && c <= '9')
Value |= (c & 15);
else
Value |= (c & 15) + 9;
++String;
}
return(Value);
}
/* BlockWindow(struct Window *Window):
*
* Block a window (show a wait mouse pointer, block
* windows, custom and system gadgets) by adding
* an invisible requester to it.
*/
VOID __regargs
BlockWindow(struct Window *Window)
{
if(Window)
{
struct Requester *InvisibleRequest = NULL;
WORD i;
Forbid();
/* Is this window already on the list? */
for(i = 0 ; i < 10 ; i++)
{
if(RequesterList[i] . RWindow == Window)
{
Permit();
return;
}
}
/* Look for an empty slot. */
for(i = 0 ; i < 10 ; i++)
{
if(!RequesterList[i] . RWindow)
{
InvisibleRequest = &RequesterList[i];
InvisibleRequest -> RWindow = (struct Window *)~0;
break;
}
}
Permit();
/* Install the wait mouse pointer. */
SetWait(Window);
/* Install the requester if possible. */
if(InvisibleRequest)
Request(InvisibleRequest,Window);
}
}
/* ReleaseWindow(struct Window *Window):
*
* Release a window blocked by `BlockWindow()'.
*/
VOID __regargs
ReleaseWindow(struct Window *Window)
{
if(Window)
{
struct Requester *InvisibleRequest = NULL;
WORD i;
/* Search all slots for the requester to block this window. */
for(i = 0 ; i < 10 ; i++)
{
if(RequesterList[i] . RWindow == Window)
{
InvisibleRequest = &RequesterList[i];
break;
}
}
/* Restore the mouse pointer. */
ClearPointer(Window);
/* If disabled, restore the window. */
if(InvisibleRequest)
{
/* End the requester activity. */
EndRequest(InvisibleRequest,Window);
/* Reset it to zeroes. */
memset(InvisibleRequest,0,sizeof(struct Requester));
}
}
}
/* BlockWindows():
*
* Block the main window and the status window (i.e. disable
* the menu and attach a wait pointer).
*/
VOID
BlockWindows()
{
if(!(BlockNestCount++))
{
BlockWindow(Window);
BlockWindow(StatusWindow);
BlockWindow(PacketWindow);
BlockWindow(FastWindow);
BlockWindow(ReviewWindow);
WeAreBlocking = TRUE;
}
}
/* ReleaseWindows():
*
* Reenable the menus and clear the wait pointer.
*/
VOID
ReleaseWindows()
{
if(!(--BlockNestCount))
{
ReleaseWindow(Window);
ReleaseWindow(StatusWindow);
ReleaseWindow(PacketWindow);
ReleaseWindow(FastWindow);
ReleaseWindow(ReviewWindow);
WeAreBlocking = FALSE;
}
}
/* LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars):
*
* Read a few bytes from a file (à la gets).
*/
LONG
LineRead(BPTR File,UBYTE *Buffer,LONG MaxChars)
{
STATIC UBYTE Data[1024];
STATIC LONG RIdx = 0,
RLen = 0;
LONG BytesRead = 0,
i;
if(File)
{
for(i = 0 ; i < MaxChars ; i++)
{
if(RIdx >= RLen)
{
RLen = Read(File,Data,1024);
RIdx = 0;
if(RLen <= 0)
{
Buffer[i] = 0;
return(BytesRead);
}
}
BytesRead++;
if((Buffer[i] = Data[RIdx++]) == '\n')
{
Buffer[i + 1] = 0;
return(BytesRead);
}
}
return(BytesRead);
}
else
RIdx = RLen = 0;
}
/* FlowInit():
*
* Set up the data flow parser. The parser scans the serial
* output data for more or less interesting modem output
* (carrier lost, connect, etc.).
*/
VOID
FlowInit()
{
FlowInfo . Changed = FALSE;
FlowInfo . NoCarrier = FlowInfo . ZModemUpload = FlowInfo . Connect = FlowInfo . Voice = FlowInfo . Ring = FlowInfo . Busy = FlowInfo . NoDialTone = FALSE;
if(Config . NoCarrier[0])
SPrintf(AttentionBuffers[0],"%s\r",Config . NoCarrier);
else
AttentionBuffers[0][0] = 0;
if(Config . Ring[0])
SPrintf(AttentionBuffers[1],"%s\r",Config . Ring);
else
AttentionBuffers[1][0] = 0;
if(Config . Voice[0])
SPrintf(AttentionBuffers[2],"%s\r",Config . Voice);
else
AttentionBuffers[2][0] = 0;
if(Config . Busy[0])
SPrintf(AttentionBuffers[6],"%s\r",Config . Busy);
else
AttentionBuffers[6][0] = 0;
if(Config . NoDialTone[0])
SPrintf(AttentionBuffers[7],"%s\r",Config . NoDialTone);
else
AttentionBuffers[7][0] = 0;
strcpy(AttentionBuffers[3],Config . Connect);
strcpy(AttentionBuffers[4],"*\030B01");
strcpy(AttentionBuffers[5],"**\030B01");
FlowCount = 0;
memset(&AttentionCount[0],0,8);
BaudPending = FALSE;
FullCheck = FALSE;
}
/* FlowFilter(UBYTE Char):
*
* Send a character through the data flow parser and look
* if it's part of a modem message.
*/
VOID
FlowFilter(UBYTE Char)
{
if(Char)
{
STATIC BYTE IgnoreChar;
BYTE i,Matches = 0,Start,End,WasOnline = Online;
/* Full data check is a lot slower than looking for
* just a single sequence (such as the `CONNECT'
* below). This mode is reserved for the dial panel.
*/
if(FullCheck)
{
Start = 0;
End = 8;
}
else
{
Start = 0;
if(UsesZModem)
End = 6;
else
End = 4;
}
/* We already got a `CONNECT' and the
* `connect auto-baud' feature is enabled.
* Continue scanning the serial output
* data for the actual baud rate.
*/
if(BaudPending)
{
if(Char >= '0' && Char <= '9')
{
BaudBuffer[BaudCount++] = Char;
if(IgnoreChar)
IgnoreChar = 0;
}
else
{
/* The scanner has found a
* non-numerical character.
* This is either a blank
* space or something else.
* The latter tells us
* that the baud rate has
* been identified and is
* ready to be used.
*/
if(Char != IgnoreChar)
{
BaudBuffer[BaudCount] = 0;
BaudPending = FALSE;
}
}
}
if(!BaudPending)
{
/* Scan all ID strings for matches. */
for(i = Start ; i < End ; i++)
{
/* This sequence is a probable
* match.
*/
if(AttentionCount[i] == FlowCount)
{
/* Does the character
* fit into the sequence?
*/
if(Char == AttentionBuffers[i][FlowCount])
{
/* Increment the
* number of matching
* characters in this
* sequence.
*/
AttentionCount[i]++;
/* Did we hit the
* last character
* in the sequence?
*/
if(AttentionBuffers[i][FlowCount + 1])
Matches++;
else
{
Matches = 0;
/* We've got a valid
* sequence, now look
* which flags to change.
*/
switch(i)
{
/* We got a `no carrier' message. */
case 0: if(Config . CheckCarrier)
{
WriteRequest -> IOSer . io_Command = SDCMD_QUERY;
DoIO(WriteRequest);
/* Are we to take a look at the carrier bit
* and if so, is the carrier still
* present?
*/
if(!(WriteRequest -> io_Status & (1 << 5)))
break;
}
if(!FlowInfo . NoCarrier)
{
FlowInfo . NoCarrier = TRUE;
FlowInfo . Changed = TRUE;
}
Online = FALSE;
/* Clear the password. */
Password[0] = 0;
UserName[0] = 0;
if(WasOnline)
{
if(CurrentPay && ChosenEntry)
LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_COST_TXT),CreateSum(CurrentPay,TRUE));
else
LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
Say(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
}
break;
/* Got another call. */
case 1: if(!FlowInfo . Ring)
{
FlowInfo . Ring = TRUE;
FlowInfo . Changed = TRUE;
}
break;
/* Got a voice call. */
case 2: if(!FlowInfo . Voice)
{
FlowInfo . Voice = TRUE;
FlowInfo . Changed = TRUE;
}
break;
/* Got a connect message. */
case 3: if(!FlowInfo . Connect)
{
FlowInfo . Connect = TRUE;
FlowInfo . Changed = TRUE;
}
if(Config . ConnectAutoBaud)
{
BaudBuffer[0] = 0;
BaudPending = TRUE;
BaudCount = 0;
IgnoreChar = ' ';
}
break;
/* Got the ZModem inquiry sequence. */
case 4:
case 5: if(!FlowInfo . ZModemUpload)
{
FlowInfo . ZModemUpload = TRUE;
FlowInfo . Changed = TRUE;
}
break;
/* Line is busy. */
case 6: if(!FlowInfo . Busy)
{
FlowInfo . Busy = TRUE;
FlowInfo . Changed = TRUE;
}
break;
case 7: if(!FlowInfo . NoDialTone)
{
FlowInfo . NoDialTone = TRUE;
FlowInfo . Changed = TRUE;
}
break;
}
}
}
}
}
/* We've got a good match (recognized
* a sequence, so reset the data flow
* scanner.
*/
if(!Matches)
{
if(FlowCount)
{
FlowCount = 0;
memset(&AttentionCount[0],0,8);
}
}
else
FlowCount++;
}
else
{
/* This checks for just a single sequence:
* the notorious `NO CARRIER'.
*/
if(AttentionCount[0] == FlowCount)
{
if(Char == AttentionBuffers[0][FlowCount])
{
AttentionCount[0]++;
if(AttentionBuffers[0][FlowCount + 1])
Matches++;
else
{
Matches = 0;
if(!FlowInfo . NoCarrier)
{
FlowInfo . NoCarrier = TRUE;
FlowInfo . Changed = TRUE;
}
Online = FALSE;
/* Clear the password. */
Password[0] = 0;
UserName[0] = 0;
if(WasOnline)
{
if(CurrentPay)
LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_COST_TXT),CreateSum(CurrentPay,TRUE));
else
LogAction(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
Say(LocaleString(MSG_TERMAUX_CARRIER_LOST_TXT));
}
}
}
}
if(!Matches)
{
if(FlowCount)
{
FlowCount = 0;
memset(&AttentionCount[0],0,8);
}
}
else
FlowCount++;
}
}
}
/* LoadMacros(UBYTE *Name,struct MacroKeys *Keys):
*
* Load the keyboard macros from a file.
*/
BYTE
LoadMacros(UBYTE *Name,struct MacroKeys *Keys)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
struct StoredProperty *Prop;
struct TermInfo *TermInfo;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_READ))
{
/* Collect version number ID if
* available.
*/
if(!PropChunks(Handle,&VersionProps[0],1))
{
/* The following line tells iffparse to stop at the
* very beginning of a `Type' chunk contained in a
* `TERM' FORM chunk.
*/
if(!StopChunk(Handle,'TERM','KEYS'))
{
/* Parse the file... */
if(!ParseIFF(Handle,IFFPARSE_SCAN))
{
/* Did we get a version ID? */
if(Prop = FindProp(Handle,'TERM','VERS'))
{
TermInfo = (struct TermInfo *)Prop -> sp_Data;
/* Is it the file format we are able
* to read?
*/
if((TermInfo -> Version > TermVersion) || (TermInfo -> Version == TermVersion && TermInfo -> Revision > TermRevision) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
{
/* Probably an older revision. */
if(TermInfo -> Version == 1 && TermInfo -> Revision < 6)
{
memset(Keys,0,sizeof(struct MacroKeys));
if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
Success = TRUE;
}
}
else
{
/* The file read pointer is positioned
* just in front of the first data
* to be read, so let's don't disappoint
* iffparse and read it.
*/
if(ReadChunkBytes(Handle,Keys,sizeof(struct MacroKeys)) == sizeof(struct MacroKeys))
Success = TRUE;
}
}
else
{
/* File was created by WriteIFFData previous
* to revision 1.4.
*/
memset(Keys,0,sizeof(struct MacroKeys));
if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
Success = TRUE;
}
}
}
}
CloseIFF(Handle);
}
Close(Handle -> iff_Stream);
}
FreeIFF(Handle);
}
return(Success);
}
/* FindThisItem(ULONG MenuID):
*
* Scan the main menu for a menuitem associated with a
* menu ID.
*/
struct MenuItem *
FindThisItem(ULONG MenuID)
{
struct Menu *FirstMenu;
struct MenuItem *FirstItem;
FirstMenu = Menu;
while(FirstMenu)
{
FirstItem = FirstMenu -> FirstItem;
while(FirstItem)
{
if((ULONG)GTMENUITEM_USERDATA(FirstItem) == MenuID)
return(FirstItem);
else
FirstItem = FirstItem -> NextItem;
}
FirstMenu = FirstMenu -> NextMenu;
}
return(NULL);
}
/* GetFileSize(UBYTE *Name):
*
* Simple routine to return the size of a file in
* bytes.
*/
LONG
GetFileSize(UBYTE *Name)
{
struct FileInfoBlock __aligned FileInfo;
BPTR FileLock;
LONG FileSize = 0;
if(FileLock = Lock(Name,ACCESS_READ))
{
if(Examine(FileLock,&FileInfo))
FileSize = FileInfo . fib_Size;
UnLock(FileLock);
}
return(FileSize);
}
/* GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect):
*
* Call the asl.library file requester to select a single or
* a couple of files.
*/
struct FileRequester *
GetFile(UBYTE *Title,UBYTE *Directory,UBYTE *Name,UBYTE *Buffer,UBYTE *Pattern,BYTE SaveFlag,BYTE MultiSelect,BYTE DirsOnly,UBYTE *OKText)
{
struct FileRequester *AslFileRequest;
BYTE Result = FALSE,
DefaultPattern = FALSE;
LONG Flags,ExtFlags = 0;
WORD i,j;
STATIC UBYTE DirBuffer[256],
PatternBuffer[256],
OtherTitle[40];
/* We use this tag array to remember the size and
* position of the asl requester window.
*/
STATIC struct {
ULONG Tag1, LeftEdge;
ULONG Tag2, TopEdge;
ULONG Tag3, Width;
ULONG Tag4, Height;
ULONG Tag5;
} Dims = {
ASL_LeftEdge, -1,
ASL_TopEdge, -1,
ASL_Width, -1,
ASL_Height, -1,
TAG_DONE
};
for(i = j = 0 ; i < strlen(Title) ; i++)
{
if(Title[i] != '_')
OtherTitle[j++] = Title[i];
}
OtherTitle[j] = 0;
Title = OtherTitle;
if(DirsOnly)
{
ExtFlags |= FIL1F_NOFILES;
if(Pattern)
ExtFlags |= FIL1F_MATCHDIRS;
}
/* Empty directory string? Revert to the last directory
* name.
*/
if(!Directory[0])
{
if(!DirBuffer[0])
{
if(!GetCurrentDirName(DirBuffer,256))
DirBuffer[0] = 0;
}
Directory = DirBuffer;
}
/* If a wildcard pattern is required, add a gadget
* to display it.
*/
if(Pattern)
{
Flags = FILF_PATGAD;
if(!Pattern[0])
{
DefaultPattern = TRUE;
if(PatternBuffer[0])
Pattern = PatternBuffer;
else
Pattern = "#?";
}
else
{
if(!strcmp(Pattern,"#?") || !Stricmp(Pattern,PatternBuffer))
{
DefaultPattern = TRUE;
Pattern = PatternBuffer;
}
}
}
else
{
Flags = 0;
Pattern = "#?";
}
/* Set the save flag if we are about to save something. */
if(SaveFlag)
Flags |= FILF_SAVE;
/* Set the multiselect bit if multiple files are
* to be selected (e.g. for batch file upload).
*/
if(MultiSelect)
Flags |= FILF_MULTISELECT;
/* Provide a standard `Ok' text if none
* specified.
*/
if(!OKText)
OKText = (SaveFlag ? LocaleString(MSG_GLOBAL_SAVE_TXT) : LocaleString(MSG_GLOBAL_OPEN_TXT));
/* Allocate the asl.library directory requester
* and display it.
*/
if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
ASL_Window, Window,
ASL_File, Name,
ASL_Dir, Directory,
ASL_Hail, Title,
ASL_FuncFlags, Flags | FILF_NEWIDCMP,
ASL_Pattern, Pattern,
ASL_OKText, OKText,
ASL_ExtFlags1, ExtFlags,
#ifdef ASLSM_FilterFunc
ASLFR_TextAttr, &DefaultFont,
#endif /* ASLSM_FilterFunc */
(Dims . LeftEdge == -1) ? TAG_DONE : TAG_MORE,&Dims))
{
if(AslRequestTags(AslFileRequest,TAG_DONE))
{
Dims . LeftEdge = AslFileRequest -> rf_LeftEdge;
Dims . TopEdge = AslFileRequest -> rf_TopEdge;
Dims . Width = AslFileRequest -> rf_Width;
Dims . Height = AslFileRequest -> rf_Height;
if(!DirsOnly)
{
/* Do we have a valid file name? */
if(AslFileRequest -> rf_File[0])
{
/* Build a legal path/file string. */
strcpy(Buffer,AslFileRequest -> rf_Dir);
AddPart((UBYTE *)Buffer,(UBYTE *)AslFileRequest -> rf_File,256);
Result = TRUE;
strcpy(DirBuffer,AslFileRequest -> rf_Dir);
}
}
else
{
if(AslFileRequest -> rf_Dir[0])
{
strcpy(Buffer,AslFileRequest -> rf_Dir);
Result = TRUE;
strcpy(DirBuffer,AslFileRequest -> rf_Dir);
}
}
}
}
/* We didn't get a file, no need to keep the
* file requester.
*/
if(!Result && AslFileRequest)
{
FreeAslRequest(AslFileRequest);
return(NULL);
}
else
{
if(DefaultPattern)
strcpy(PatternBuffer,AslFileRequest -> rf_Pat);
return(AslFileRequest);
}
}
/* MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...):
*
* Really quite simple varargs version of Intuition's
* EasyRequest requester.
*/
WORD __stdargs
MyEasyRequest(struct Window *Window,UBYTE *Text,UBYTE *Gadgets,...)
{
struct EasyStruct Easy;
WORD Result;
ULONG IDCMP = NULL;
va_list VarArgs;
/* Standard data. */
Easy . es_StructSize = sizeof(struct EasyStruct);
Easy . es_Flags = NULL;
Easy . es_Title = (UBYTE *)LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);
Easy . es_TextFormat = (UBYTE *)Text;
Easy . es_GadgetFormat = (UBYTE *)Gadgets;
/* Use the argument array to build the
* requester and display it.
*/
va_start(VarArgs,Gadgets);
Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs);
va_end(VarArgs);
return(Result);
}
/* SelectTime():
*
* Searches for the correct unit/pay conversion values.
*/
VOID
SelectTime(struct PhoneEntry *SomeEntry)
{
struct TimeDateNode *TimeDateNode;
struct DateStamp __aligned Date;
struct ClockData ClockData;
BYTE FoundOne = FALSE;
/* Obtain current time and date. */
DateStamp(&Date);
/* Convert into a more suitable form (note: seconds are
* required as an input value).
*/
Amiga2Date(Date . ds_Days * 86400 + Date . ds_Minute * 60 + Date . ds_Tick / TICKS_PER_SECOND,&ClockData);
/* Apparently, in the US the week starts with Sunday, we'll
* wrap the week around to let it start with Monday.
*/
if(ClockData . wday)
ClockData . wday--;
else
ClockData . wday = 6;
/* Change the month, too... */
ClockData . month--;
/* First step: search for current day. */
TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
/* Skip first entry. */
TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
while(TimeDateNode -> VanillaNode . ln_Succ)
{
/* Does it match a specific date? */
if(TimeDateNode -> TimeDate . Month == ClockData . month && TimeDateNode -> TimeDate . Day == ClockData . mday)
{
FoundOne = TRUE;
break;
}
TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
}
/* Second step: search for week day settings. */
if(!FoundOne)
{
TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
/* Skip first entry. */
TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
while(TimeDateNode -> VanillaNode . ln_Succ)
{
/* Does it match a specific day? */
if(TimeDateNode -> TimeDate . Month == -1 && (TimeDateNode -> TimeDate . Day & (1 << ClockData . wday)))
{
FoundOne = TRUE;
break;
}
TimeDateNode = (struct TimeDateNode *)TimeDateNode -> VanillaNode . ln_Succ;
}
}
/* Third step: use default settings. */
if(!FoundOne)
TimeDateNode = (struct TimeDateNode *)SomeEntry -> TimeDateList . mlh_Head;
/* Fill in the remaining data. */
PayPerUnit[0] = TimeDateNode -> TimeDate . PayPerUnit[0];
PayPerUnit[1] = TimeDateNode -> TimeDate . PayPerUnit[1];
SecPerUnit[0] = TimeDateNode -> TimeDate . SecPerUnit[0];
SecPerUnit[1] = TimeDateNode -> TimeDate . SecPerUnit[1];
TimeOfDay[0] = TimeDateNode -> TimeDate . TimeOfDay[0];
TimeOfDay[1] = TimeDateNode -> TimeDate . TimeOfDay[1];
}
/* Raise(UWORD Colour):
*
* Make an RGB value brighter.
*/
STATIC UWORD __regargs
Raise(UWORD Colour)
{
WORD r,g,b;
r = (Colour >> 8) + 4;
g = ((Colour >> 4) & 0xF) + 4;
b = ((Colour ) & 0xF) + 4;
if(r > 15)
r = 15;
if(g > 15)
g = 15;
if(b > 15)
b = 15;
return(r << 8 | g << 4 | b);
}
/* VisualBeep():
*
* Handle the visual part of the display beep.
*/
STATIC BYTE
VisualBeep()
{
struct UCopList *UserCopperList;
/* Create a user copper list. */
if(UserCopperList = (struct UCopList *)AllocMem(sizeof(struct UCopList),MEMF_ANY|MEMF_CLEAR))
{
/* Initialize for 35 commands. */
if(UCopperListInit(UserCopperList,1 + 16 + 1 + 16 + 1))
{
WORD i;
/* Wait until first line of window. */
CWAIT(UserCopperList,Window -> TopEdge,0);
/* Set the light colours. */
for(i = 0 ; i < 16 ; i++)
CMOVE(UserCopperList,custom . color[i],Raise(GetRGB4(Screen -> ViewPort . ColorMap,i)));
/* Wait until bottom of window. */
CWAIT(UserCopperList,Window -> TopEdge + Window -> Height - 1,0);
/* Set the standard colours. */
for(i = 0 ; i < 16 ; i++)
CMOVE(UserCopperList,custom . color[i],GetRGB4(Screen -> ViewPort . ColorMap,i));
/* Finish list. */
CEND(UserCopperList);
/* Install user copper list... */
Screen -> ViewPort . UCopIns = UserCopperList;
/* ...and display it. */
RethinkDisplay();
return(TRUE);
}
else
FreeMem(UserCopperList,sizeof(struct UCopList));
}
return(FALSE);
}
/* PrintStatusLine(struct RastPort *RPort,STRPTR String):
*
* Print a string into the status line,
* checks first to see if the Text() routine is
* likely to wait.
*/
STATIC VOID __regargs
PrintStatusLine(struct RastPort *RPort,STRPTR String)
{
if(AttemptLockLayerRom(RPort -> Layer))
{
Text(RPort,String,strlen(String));
UnlockLayerRom(RPort -> Layer);
}
}
/* StatusServer():
*
* Asynchronous process to continuosly display the current
* terminal settings.
*/
VOID __saveds
StatusServer()
{
STATIC struct timeval OnlineTime;
STATIC UBYTE OnlineBuffer[20];
STATIC BYTE GotOnline = FALSE,
WasOnline = FALSE,
ShowPay = FALSE,
FlagBit = FALSE;
STATIC LONG SecCount = 0,
BeepCount = 0;
struct RastPort *RPort;
UBYTE Buffer[80];
struct timerequest *TimeRequest;
struct MsgPort *TimePort;
BYTE Background = FALSE,
FlashIt = FALSE,
SetColours = FALSE,
StandardColours = TRUE,
KeepGoing = TRUE,
Beeping = FALSE;
BYTE LastProtocol[40],
ProtocolBuffer[20],
i;
BYTE LastFont = -1,
LastEmulation = -1,
LastBitsPerChar = -1,
LastParity = -1,
LastStopBits = -1,
LastStatus = -1;
LONG LastBaud = -1;
LONG ThisHour,ThisMinute,TestTime;
LastProtocol[0] = 0;
LocalizeString(ConfigEmulation,MSG_TERMAUX_ANSI_VT102_TXT,MSG_TERMAUX_EXTERNAL_TXT);
LocalizeString(ConfigParity,MSG_TERMAUX_NONE_TXT,MSG_TERMAUX_SPACE_TXT);
LocalizeString(ConfigStatus,MSG_TERMAUX_READY_TXT,MSG_TERMAUX_HANG_UP_TXT);
/* Create a timer device request. */
if(TimePort = (struct MsgPort *)CreateMsgPort())
{
if(TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest)))
{
if(!OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,0))
{
/* Signal our father process
* that we're running.
*/
Signal(ThisProcess,SIGBREAKF_CTRL_C);
if(StatusWindow)
{
RPort = StatusWindow -> RPort;
if(Config . StatusLine == STATUSLINE_COMPRESSED)
{
MoveSingle(0);
Text(RPort," · · · · · · 00:00:00",73);
}
else
{
MoveItem(64,1);
Text(RPort,"00:00:00",8);
}
}
else
RPort = NULL;
/* Keep on displaying. */
while(KeepGoing)
{
/* Are we to quit? */
if(SetSignal(0,0) & SIGBREAKF_CTRL_C)
{
KeepGoing = FALSE;
SetSignal(0,SIGBREAKF_CTRL_C);
}
/* Get the current time. */
TimeRequest -> tr_node . io_Command = TR_GETSYSTIME;
DoIO(TimeRequest);
/* A connection has just
* been established.
*/
if(Online && !GotOnline)
{
OnlineTime = TimeRequest -> tr_time;
GotOnline = TRUE;
SecCount = 0;
FlagBit = FALSE;
}
/* Print the current time. */
ThisHour = (TimeRequest -> tr_time . tv_secs % 86400) / 3600;
ThisMinute = (TimeRequest -> tr_time . tv_secs % 3600) / 60;
if(RPort)
{
SPrintf(Buffer,"%02ld:%02ld:%02ld",ThisHour,ThisMinute,TimeRequest -> tr_time . tv_secs % 60);
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(54);
else
MoveItem(64,0);
PrintStatusLine(RPort,Buffer);
}
if(Online)
{
STATIC struct timeval LastTime;
struct timeval TempTime;
WasOnline = TRUE;
if(ChosenEntry)
{
if(!(ThisMinute % 10) && !(TimeRequest -> tr_time . tv_secs % 60))
{
ChosenInUse = TRUE;
SelectTime(ChosenEntry);
ChosenInUse = FALSE;
}
TestTime = ThisHour * 6 + ThisMinute / 10;
if(TestTime >= TimeOfDay[0] && TestTime <= TimeOfDay[1])
PreferredTime = 0;
else
{
if(TestTime >= TimeOfDay[1] && TestTime <= TimeOfDay[0])
PreferredTime = 1;
else
{
if(TestTime >= TimeOfDay[0] && TestTime >= TimeOfDay[1])
{
if(TimeOfDay[0] > TimeOfDay[1])
PreferredTime = 0;
else
PreferredTime = 1;
}
else
{
if(TestTime <= TimeOfDay[0] && TestTime <= TimeOfDay[1])
{
if(TimeOfDay[0] > TimeOfDay[1])
PreferredTime = 0;
else
PreferredTime = 1;
}
}
}
}
if(!CurrentPay)
CurrentPay = PayPerUnit[PreferredTime];
FlagBit ^= TRUE;
if(!FlagBit)
{
if(SecPerUnit[PreferredTime])
{
if(SecCount == SecPerUnit[PreferredTime])
{
SecCount = 0;
CurrentPay += PayPerUnit[PreferredTime];
}
}
SecCount++;
}
}
/* Show the time
* we have been online
* yet.
*/
TempTime = TimeRequest -> tr_time;
if(TempTime . tv_secs != LastTime . tv_secs)
{
LastTime = TempTime;
SubTime(&TempTime,&OnlineTime);
if(!(TempTime . tv_secs % 5) && TempTime . tv_secs)
ShowPay ^= TRUE;
SPrintf(OnlineBuffer,"%02ld:%02ld:%02ld",(TempTime . tv_secs % 86400) / 3600,(TempTime . tv_secs % 3600) / 60,TempTime . tv_secs % 60);
if(ShowPay && CurrentPay && ChosenEntry)
{
SPrintf(Buffer,"%s ",CreateSum(CurrentPay,FALSE));
Buffer[8] = 0;
}
else
strcpy(Buffer,OnlineBuffer);
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(65);
else
MoveItem(64,1);
PrintStatusLine(RPort,Buffer);
}
}
}
else
{
if(WasOnline)
{
WasOnline = FALSE;
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(65);
else
MoveItem(64,1);
PrintStatusLine(RPort,OnlineBuffer);
}
}
if(GotOnline)
GotOnline = FALSE;
}
/* Take care of the visual beep
* if enabled.
*/
if(Beeping)
{
if(!(BeepCount--))
{
Beeping = FALSE;
/* Remove the copper list. */
FreeVPortCopLists(&Screen -> ViewPort);
/* Really remove it. */
RemakeDisplay();
/* Clear the signal bit. */
SetSignal(0,SIGBREAKF_CTRL_D);
}
}
/* Are we to show a visual beep? */
if(SetSignal(0,0) & SIGBREAKF_CTRL_D)
{
if(Config . SystemBeep)
{
DisplayBeep(Screen);
SetSignal(0,SIGBREAKF_CTRL_D);
}
else
{
if(!Beeping)
{
if(VisualBeep())
{
Beeping = TRUE;
BeepCount = 1;
SetSignal(0,SIGBREAKF_CTRL_D);
}
}
}
}
/* Display the current terminal
* status.
*/
if(LastStatus != Status)
{
LastStatus = Status;
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(0);
else
MoveItem(7,0);
PrintStatusLine(RPort,ConfigStatus[LastStatus]);
}
}
/* Show the current transfer
* protocol.
*/
if(strcmp(LastProtocol,FilePart(Config . Protocol)))
{
strcpy(LastProtocol,FilePart(Config . Protocol));
strcpy(ProtocolBuffer," ");
for(i = 0 ; i < 8 ; i++)
{
if(!LastProtocol[i + 3] || LastProtocol[i + 3] == '.')
break;
else
ProtocolBuffer[i] = LastProtocol[i + 3];
}
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(23);
else
MoveItem(25,0);
PrintStatusLine(RPort,ProtocolBuffer);
}
}
/* Show the current baud
* rate.
*/
if(LastBaud != Config . BaudRate)
{
LastBaud = Config . BaudRate;
if(RPort)
{
extern APTR LocaleBase;
if(LocaleBase)
SPrintf(Buffer,"%lD ",LastBaud);
else
SPrintf(Buffer,"%ld ",LastBaud);
Buffer[7] = 0;
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(36);
else
MoveItem(47,0);
PrintStatusLine(RPort,Buffer);
}
}
/* Show the current
* terminal font.
*/
if(LastFont != Config . Font)
{
LastFont = Config . Font;
if(RPort)
{
if(Config . StatusLine != STATUSLINE_COMPRESSED)
{
MoveItem(7,1);
PrintStatusLine(RPort,ConfigFont[LastFont]);
}
}
}
/* Show the current terminal
* emulation.
*/
if(Config . Emulation == 3)
{
LastEmulation = Config . Emulation;
if(RPort)
{
SPrintf(Buffer,"%s ",EmulationName);
Buffer[10] = 0;
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(10);
else
MoveItem(25,1);
PrintStatusLine(RPort,Buffer);
}
}
else
{
if(LastEmulation != Config . Emulation)
{
LastEmulation = Config . Emulation;
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
MoveSingle(10);
else
MoveItem(25,1);
PrintStatusLine(RPort,ConfigEmulation[LastEmulation]);
}
}
}
/* Show the current serial
* parameters (parity, etc).
*/
if(LastBitsPerChar != Config . BitsPerChar || LastParity != Config . Parity || LastStopBits != Config . StopBits)
{
LastBitsPerChar = Config . BitsPerChar;
LastParity = Config . Parity;
LastStopBits = Config . StopBits;
if(RPort)
{
if(Config . StatusLine == STATUSLINE_COMPRESSED)
{
STATIC UBYTE Parities[] =
{
'N','E','O','M','S'
};
MoveSingle(46);
SPrintf(Buffer,"%ld-%lc-%ld",LastBitsPerChar,Parities[LastParity],LastStopBits);
}
else
{
SPrintf(Buffer,"%ld-%s-%ld ",LastBitsPerChar,ConfigParity[LastParity],LastStopBits);
Buffer[9] = 0;
MoveItem(47,1);
}
PrintStatusLine(RPort,Buffer);
}
}
/* Wait another half a second. */
if(KeepGoing)
{
ULONG Mask;
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = 0;
TimeRequest -> tr_time . tv_micro = MILLION / 2;
SendIO(TimeRequest);
FOREVER
{
Mask = Wait(SIGBREAKF_CTRL_D | (1 << TimePort -> mp_SigBit));
if(Mask & SIGBREAKF_CTRL_D)
{
if(Config . SystemBeep)
{
DisplayBeep(Screen);
SetSignal(0,SIGBREAKF_CTRL_D);
}
else
{
if(!Beeping)
{
if(VisualBeep())
{
Beeping = TRUE;
BeepCount = 1;
}
}
}
}
if(Mask & (1 << TimePort -> mp_SigBit))
{
WaitIO(TimeRequest);
break;
}
}
}
/* Make the colours blink. */
if(Screen == IntuitionBase -> FirstScreen)
{
/* No main screen window active? */
if(StatusWindow)
{
if(!(Window -> Flags & WFLG_WINDOWACTIVE) && !(StatusWindow -> Flags & WFLG_WINDOWACTIVE))
StandardColours = TRUE;
}
else
{
if(!(Window -> Flags & WFLG_WINDOWACTIVE))
StandardColours = TRUE;
}
/* Menu button pressed or window disabled? */
if(Window -> Flags & (WFLG_MENUSTATE|WFLG_INREQUEST))
StandardColours = TRUE;
Background = FALSE;
}
else
{
if(!Background)
StandardColours = TRUE;
Background = TRUE;
}
if(StandardColours)
{
if(!SetColours)
{
LoadRGB4(VPort,Config . Colours,16);
SetColours = TRUE;
}
StandardColours = FlashIt = FALSE;
}
else
{
/* Are we to flash the display? */
if(!(Config . DisableBlinking & ~TERMINAL_FASTER))
{
if(Screen == IntuitionBase -> FirstScreen)
{
if(FlashIt)
{
LoadRGB4(VPort,BlinkColours,16);
SetColours = FALSE;
}
else
{
LoadRGB4(VPort,Config . Colours,16);
SetColours = TRUE;
}
}
FlashIt ^= TRUE;
}
}
}
CloseDevice(TimeRequest);
}
DeleteIORequest(TimeRequest);
}
DeleteMsgPort(TimePort);
}
/* Signal the father process that we're done
* and quietly remove ourselves.
*/
Forbid();
Signal(ThisProcess,SIGBREAKF_CTRL_C);
StatusProcess = NULL;
}
/* CloseWindowSafely(struct Window *Window):
*
* Close a window freeing all messages pending at
* its user port (taken from example source code
* published once upon a time in Amiga Mail).
*/
VOID
CloseWindowSafely(struct Window *Window)
{
struct IntuiMessage *IntuiMessage;
struct Node *Successor;
Forbid();
IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
{
if(IntuiMessage -> IDCMPWindow == Window)
{
Remove(IntuiMessage);
ReplyMsg((struct Message *)IntuiMessage);
}
IntuiMessage = (struct IntuiMessage *)Successor;
}
Window -> UserPort = NULL;
ModifyIDCMP(Window,NULL);
Permit();
CloseWindow(Window);
}
/* WaitTime(LONG Secs,LONG Micros):
*
* Wait a given period of time.
*/
VOID
WaitTime(LONG Secs,LONG Micros)
{
TimeRequest -> tr_node . io_Command = TR_ADDREQUEST;
TimeRequest -> tr_time . tv_secs = Secs;
TimeRequest -> tr_time . tv_micro = Micros;
DoIO(TimeRequest);
}
/* GetEnvDOS(UBYTE *Name,UBYTE *Buffer):
*
* Get the contents of a vanilla AmigaDOS environment
* variable.
*/
UBYTE *
GetEnvDOS(UBYTE *Name,UBYTE *Buffer)
{
LONG Size;
BPTR File,SomeLock;
Buffer[0] = 0;
/* Is ENV: present? */
if(SomeLock = Lock("Env:",ACCESS_READ))
{
UBYTE SomeBuffer[80];
UnLock(SomeLock);
strcpy(SomeBuffer,"Env:");
strcat(SomeBuffer,Name);
/* Open the file. */
if(File = Open(SomeBuffer,MODE_OLDFILE))
{
/* Read the contents. */
Size = Read(File,Buffer,256);
Close(File);
if(Size > 0)
{
Buffer[Size] = 0;
return(Buffer);
}
}
}
return(NULL);
}
/* SetEnvDOS(UBYTE *Name,UBYTE *Value):
*
* Set the contents of a vanilla AmigaDOS environment
* variable.
*/
BYTE
SetEnvDOS(UBYTE *Name,UBYTE *Value)
{
UBYTE Buffer[80],*Destination;
LONG Length = 0;
BPTR File,FileLock;
BYTE Success = FALSE;
WORD i;
for(i = 0 ; i < 2 ; i++)
{
if(i)
Destination = "EnvArc:";
else
Destination = "Env:";
/* Is ENV:/ENVARC: present? */
if(FileLock = Lock(Destination,ACCESS_READ))
{
UnLock(FileLock);
strcpy(Buffer,Destination);
strcat(Buffer,Name);
/* There already is a variable of that
* name in the environment storage
* directory.
*/
if(FileLock = Lock(Buffer,ACCESS_WRITE))
{
UnLock(FileLock);
/* Delete the variable. */
if(!DeleteFile(Buffer))
{
Success = FALSE;
continue;
}
}
/* Set the new variable. */
if(Length = strlen(Value))
{
if(File = Open(Buffer,MODE_NEWFILE))
{
if(Write(File,Value,Length) != Length)
{
Close(File);
DeleteFile(Buffer);
Success = FALSE;
}
else
{
Close(File);
SetProtection(Buffer,FIBF_EXECUTE);
Success = TRUE;
}
}
else
Success = FALSE;
}
else
Success = TRUE;
}
else
Success = FALSE;
}
return(Success);
}
/* BumpWindow(struct Window *SomeWindow):
*
* Bring a window to the front (and shift the screen
* back to its initial position).
*/
VOID
BumpWindow(struct Window *SomeWindow)
{
if(SomeWindow -> WScreen -> LeftEdge > 0)
{
if(SomeWindow -> WScreen -> TopEdge > 0)
MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,-SomeWindow -> WScreen -> TopEdge);
else
MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,0);
}
else
{
if(SomeWindow -> WScreen -> TopEdge > 0)
MoveScreen(SomeWindow -> WScreen,0,-SomeWindow -> WScreen -> TopEdge);
}
ScreenToFront(SomeWindow -> WScreen);
ActivateWindow(SomeWindow);
}
/* BumpDefault():
*
* Bring the current default screen to the front.
*/
VOID
BumpDefault()
{
struct Screen *DefaultScreen;
if(DefaultScreen = (struct Screen *)LockPubScreen(NULL))
{
MoveScreen(DefaultScreen,-DefaultScreen -> LeftEdge,-DefaultScreen -> TopEdge);
ScreenToFront(DefaultScreen);
UnlockPubScreen(NULL,DefaultScreen);
}
}
/* WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
*
* Write data to an IFF file (via iffparse.library).
*/
BYTE
WriteIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
/* Allocate a handle. */
if(Handle = AllocIFF())
{
/* Open an output stream. */
if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
{
/* Tell iffparse that this is
* a DOS handle.
*/
InitIFFasDOS(Handle);
/* Open the handle for writing. */
if(!OpenIFF(Handle,IFFF_WRITE))
{
/* Push outmost chunk onto stack. */
if(!PushChunk(Handle,'TERM','FORM',IFFSIZE_UNKNOWN))
{
/* Add a version identifier. */
if(!PushChunk(Handle,0,'VERS',IFFSIZE_UNKNOWN))
{
struct TermInfo TermInfo;
TermInfo . Version = TermVersion;
TermInfo . Revision = TermRevision;
/* Write the version data. */
if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
{
/* Pop the version chunk, i.e. write it to the file. */
if(PopChunk(Handle))
Success = FALSE;
else
{
/* Push the real data chunk on the stack. */
if(!PushChunk(Handle,0,Type,IFFSIZE_UNKNOWN))
{
/* Write the data. */
if(WriteChunkBytes(Handle,Data,Size) == Size)
Success = TRUE;
/* Pop the data chunk. */
if(PopChunk(Handle))
Success = FALSE;
}
else
Success = FALSE;
}
}
else
Success = FALSE;
}
/* Seems that we're done, now try to pop the FORM chunk
* and return.
*/
if(PopChunk(Handle))
Success = FALSE;
}
/* Close the handle (flush any pending data). */
CloseIFF(Handle);
}
/* Close the DOS handle itself. */
Close(Handle -> iff_Stream);
}
/* And free the IFF handle. */
FreeIFF(Handle);
}
if(Success)
SetProtection(Name,FIBF_EXECUTE);
return(Success);
}
/* ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type):
*
* Read data from a `TERM' FORM chunk contained in an IFF file.
*/
BYTE
ReadIFFData(UBYTE *Name,APTR Data,LONG Size,ULONG Type)
{
struct IFFHandle *Handle;
BYTE Success = FALSE;
struct StoredProperty *Prop;
struct TermInfo *TermInfo;
if(Handle = AllocIFF())
{
if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
{
InitIFFasDOS(Handle);
if(!OpenIFF(Handle,IFFF_READ))
{
/* Collect version number ID if
* available.
*/
if(!PropChunks(Handle,&VersionProps[0],1))
{
/* The following line tells iffparse to stop at the
* very beginning of a `Type' chunk contained in a
* `TERM' FORM chunk.
*/
if(!StopChunk(Handle,'TERM',Type))
{
/* Parse the file... */
if(!ParseIFF(Handle,IFFPARSE_SCAN))
{
/* Did we get a version ID? */
if(Prop = FindProp(Handle,'TERM','VERS'))
{
TermInfo = (struct TermInfo *)Prop -> sp_Data;
/* Is it the file format we are able
* to read?
*/
if((TermInfo -> Version > TermVersion) || (TermInfo -> Version == TermVersion && TermInfo -> Revision > TermRevision) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
Success = FALSE;
else
{
struct ContextNode *Chunk = CurrentChunk(Handle);
if(Chunk -> cn_Size < Size)
Size = Chunk -> cn_Size;
/* The file read pointer is positioned
* just in front of the first data
* to be read, so let's don't disappoint
* iffparse and read it.
*/
if(ReadChunkBytes(Handle,Data,Size) == Size)
Success = TRUE;
}
}
}
}
}
CloseIFF(Handle);
}
Close(Handle -> iff_Stream);
}
FreeIFF(Handle);
}
return(Success);
}
/* PushWindow(struct Window *Window):
*
* Push/PopWindow implement a single lifo window stack
* which always updates the window to activate when
* LSHIFT+RSHIFT+RETURN is pressed. This routine will
* push a window on the stack.
*/
VOID
PushWindow(struct Window *Window)
{
if(WindowStackPtr < 5)
{
WindowStack[WindowStackPtr++] = Window;
TopWindow = Window;
}
}
/* PopWindow():
*
* Remove topmost window from window stack.
*/
VOID
PopWindow()
{
if(WindowStackPtr > 0)
{
WindowStackPtr--;
if(WindowStackPtr)
TopWindow = WindowStack[WindowStackPtr - 1];
else
TopWindow = Window;
}
}